﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using ZooKeeperNet;

namespace DistributedLock
{
    public class ExclusiveLock
    {
        internal ExclusiveLock(ZKServer server)
        {
            this.server = server;
        }

        private ZKServer server;

        /// <summary>
        /// 尝试获取锁
        /// 返回true表示当前线程拿到了锁
        /// 反之未拿到
        /// </summary>
        /// <returns></returns>
        public bool TryEnter(string node)
        {
            if (string.IsNullOrWhiteSpace(node))
            {
                return false;
            }

            //表示有并发控制
            if (server.Limit > 0)
            {
                if (this.CanContinue(node) == false)
                {
                    return false;
                }
            }

            var prevNode = ZKUtility.GetPrevNode(node);
            if (!string.IsNullOrWhiteSpace(prevNode))
            {
                ZKClient.Client.Exists(prevNode, new ExclusiveWatcher());
                if (ZKClient.Client.Exists(prevNode, false) == null)
                {
                    return true;
                }
            }

            var parentNode = ZKUtility.GetParentNode(node);
            var lowestNode = ZKUtility.GetLowestNode(parentNode);

            Console.WriteLine("node is " + node);
            Console.WriteLine("lowestNode is " + lowestNode);

            if (node == lowestNode)
            {
                return true;
            }
            else
            {
                Mutex.Wait(node);
                return this.WaitLock(node);
            }
        }

        /// <summary>
        /// 尝试获取锁
        /// 返回true表示当前线程拿到了锁
        /// 反之未拿到
        /// </summary>
        /// <returns></returns>
        public bool TryEnter2(string node)
        {
            if (string.IsNullOrWhiteSpace(node))
            {
                return false;
            }

            //表示有并发控制
            if (server.Limit > 0)
            {
                if (this.CanContinue(node) == false)
                {
                    return false;
                }
            }

            var prevNode = ZKUtility.GetPrevNode(node);
            if (!string.IsNullOrWhiteSpace(prevNode))
            {
                ZKClient.Client.Exists(prevNode, new ExclusiveWatcher());
                if (ZKClient.Client.Exists(prevNode, false) == null)
                {
                    return true;
                }
            }

            var parentNode = ZKUtility.GetParentNode(node);
            var lowestNode = ZKUtility.GetLowestNode(parentNode);

            Console.WriteLine("node is " + node);
            Console.WriteLine("lowestNode is " + lowestNode);

            if (node == lowestNode)
            {
                return true;
            }
            else
            {
                Mutex.Wait(node);
                return this.WaitLock(node);
            }
        }

        private bool WaitLock(string node)
        {
            var parentNode = ZKUtility.GetParentNode(node);
            var lowestNode = ZKUtility.GetLowestNode(parentNode);

            Console.WriteLine("node is " + node);
            Console.WriteLine("lowestNode is " + lowestNode);

            if (node == lowestNode)
            {
                return this.TryEnter(node);
            }

            return false;
        }

        /// <summary>
        /// 创建当前节点的线程能否继续
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        internal bool CanContinue(string node)
        {
            if (string.IsNullOrWhiteSpace(node))
            {
                return false;
            }

            var processedCount = ExclusiveLock.GetProcessedCount(node);
            return processedCount < server.Limit;
        }

        /// <summary>
        /// 释放排它锁
        /// </summary>
        /// <param name="node"></param>
        public void Exit(string node)
        {
            try
            {
                ZKServer.DeleteNode(node);
            }
            finally
            {
                this.DoCounter(node);
            }
        }

        /// <summary>
        /// 节点计数
        /// </summary>
        /// <param name="node"></param>
        public void DoCounter(string node)
        {
            var parentNode = ZKUtility.GetParentNode(node);
            var parentNodeValue = ZKUtility.GetNodeValue(parentNode);
            if (string.IsNullOrWhiteSpace(parentNodeValue))
            {
                ZKUtility.SetNodeValue(parentNode, "1");
            }
            else
            {
                var count = 1;
                int.TryParse(parentNodeValue, out count);
                count++;
                ZKUtility.SetNodeValue(parentNode, count.ToString());
            }
        }

        /// <summary>
        /// 获取当前节点已经并发完成的次数
        /// </summary>
        /// <returns></returns>
        public static int GetProcessedCount(string node)
        {
            var parentNode = ZKUtility.GetParentNode(node);
            var parentNodeValue = ZKUtility.GetNodeValue(parentNode);
            var count = 0;
            int.TryParse(parentNodeValue, out count);
            return count;
        }
    }
}
